#ifndef INI_INCLUDE_H
#define INI_INCLUDE_H

#include <string>
#include <map>
#include <vector>
#include <fstream>
#include <string.h>

using std::string;
using std::map;
using std::vector;
using std::fstream;
using std::pair;

class CIni
{
public:
    CIni(unsigned int lineMaxLen = 1024):m_lineMaxLen(lineMaxLen)
    {}

    CIni(const string& path,unsigned int lineMaxLen = 1024):m_lineMaxLen(lineMaxLen)
    {
        parse(path);
    }

    // 获取配置值
    string getString(const string& section,const string& option,const string& defaultVal = "");
    // 把另一个配置文件中的配置，添加到本配置
    // 遇到重复的，使用最新的值
    bool append(const string& path,bool sec_overwrite = false,unsigned int lineMaxLen = 1024);

    void enumAllSection(map<string,map<string,string> >& setting)
    {
        setting = m_settingSec;
    }
    // 获取所有的节点名
    int enumAllSection(vector<string> &setting);
    // 获取某个段的所有配置
    void enumSection(const string& section,map<string,string>& setting);
    // 获取某个section下以前缀字符串开头的一些配置，不支持通配符
    // 前缀字符串必须是完整的某个层级,比如 logging.level.
    void enumSection(const string& section,const string& prefix,map<string,string>& setting);
private:
    string& trim(string& str, const string& trimStr = " \r\n\t");
    // 注释以;或#或//开头
    bool parse(const string& path,bool sec_overwrite = false);

    unsigned int        m_lineMaxLen;
    // 统一储存
    map<string,string>  m_setting;
    // 按section存储
    map<string,map<string,string> > m_settingSec;
};

inline string CIni::getString(const string& section,const string& option,const string& defaultVal)
{
    string key(section + "." + option);
    map<string,string>::iterator it = m_setting.find(key);
    if (it != m_setting.end())
        return it->second;

    return defaultVal;
}

inline int CIni::enumAllSection(vector<string> &setting)
{
    int cnt = 0;
    setting.clear();
    for(map<string, map<string, string> >::iterator it = m_settingSec.begin();
        it != m_settingSec.end(); ++it)
    {
        setting.push_back(it->first);
        ++cnt;
    }
    return cnt;
}

inline void CIni::enumSection(const string& section,map<string,string>& setting)
{
    map<string,map<string,string> >::iterator itSec;
    itSec = m_settingSec.find(section);
    if (itSec == m_settingSec.end())
        return;
    setting = itSec->second;
}

inline void CIni::enumSection(const string& section,const string& prefix,
        map<string,string>& setting)
{
    string tmppref(prefix);
    if (!tmppref.empty() && tmppref[tmppref.length() - 1] != '.')
        tmppref = tmppref + ".";

    map<string,string>::iterator it;
    map<string,string> sectionSetting;
    enumSection(section,sectionSetting);

    for(it = sectionSetting.begin(); it != sectionSetting.end(); ++it)
    {
        if ( it->first.find(tmppref) == 0)
            setting[it->first] = it->second;
    }
}

inline bool CIni::append(const string& path,bool sec_overwrite,unsigned int lineMaxLen)
{
    if (m_lineMaxLen < lineMaxLen)
        m_lineMaxLen = lineMaxLen;

    return parse(path,sec_overwrite);
}

inline string& CIni::trim(string& str, const string& trimStr /* = " \r\n\t" */)
{
    size_t len = str.length();
    size_t begin = 0,end=len;
    
    while(begin < len)
    {
        if (trimStr.find(str[begin]) == string::npos)
            break;
        ++begin;
    }
    while(end - 1 > 0 && end - 1 > begin)
    {
        if (trimStr.find(str[end - 1]) == string::npos)
            break;
        --end;
    }
    
    str = str.substr(begin,end - begin);
    return str;
}

inline bool CIni::parse(const string& path,bool sec_overwrite)
{
    // 注释以 #或;开始，不支持行尾及行中注释
    if (path.empty()) return false;

    fstream f(path.c_str());
    if (!f.good()) return false;
    
    char* buf = new char[m_lineMaxLen];
    string section;
    map<string,string> sectionSetting;
    map<string,string>::iterator itsec;
    while(!f.eof())
    {
        memset(buf,0,m_lineMaxLen);
        f.getline(buf,m_lineMaxLen);
        
        string str(buf);
        trim(str);
        
        if (str.empty())
            continue;
        // 保存段名
        if (str[0] == '[')
        {
            size_t pos = str.find("]");
            if (pos != string::npos)
            {
                if (!sectionSetting.empty())
                {
                    // 把后面的插入原有的值
                    if (sec_overwrite)
                    {
                        m_settingSec[section] = sectionSetting;
                    }
                    else
                    {
                        for(itsec = sectionSetting.begin(); itsec != sectionSetting.end(); ++itsec)
                            m_settingSec[section][itsec->first] = itsec->second;
                    }
                    sectionSetting.clear();
                }
                
                str = str.substr(1,pos - 1);
                section = trim(str);
            }
            continue;
        }
        
        // 去掉单行注释
        if (str.size() > 1 
           && (str[0] == '#'
               || (str[0] == '/' && str[1] == '/')
               || str[0] == ';'
              )
           )
        {
            continue;
        }
        
        // 去掉;结尾符
        if (str[str.size() - 1] == ';')
            str.resize(str.size() - 1);

        // 解析选项及值
        size_t delimPos;
        delimPos = str.find("=");
        if (delimPos == string::npos)
            continue;

        string opt = str.substr(0,delimPos);
        string val = str.substr(delimPos + 1);
        if (delimPos == str.size() )
        {
            sectionSetting[trim(opt)] = "";
            m_setting[section + "." + trim(opt) ] = "";
        }
        else
        {
            sectionSetting[trim(opt)] = trim(val);
            m_setting[section + "." + trim(opt) ] = trim(val);
        }
    }
    // 最后一个section
    if (!sectionSetting.empty())
    {
        m_settingSec[section] = sectionSetting;
        sectionSetting.clear();
    }
    
    delete []buf;
    f.close();

    return true;
}

#endif







